package com.atguigu.gulimall.search.thread;

import java.util.concurrent.*;

/**
 * @author houChen
 * @date 2021/11/26 20:26
 * @Description:
 */
public class ThreadTest {

    //保证当前系统中线程池只有一两个，每个异步任务直接提交给线程池
    public static ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*
        继承Thread
        实现Runnable接口
        实现Callable接口 + FutrueTask（可以拿到结果处理异常）
        线程池
            1、创建
                1) Executor
                2)





        我们以后在业务代码中，1-3 启动线程的方式都不用。将是所有的多线程异步任务都交给线程池来处理

        区别：
        1.2 不能得到返回值
        1.2.3 都不能控制资源 （每次都需要new一个线程）
        4可以控制资源，使系统性能稳定 （可以重复利用线程池中的线程，当一千万个异步任务进来，会等待线程池中的线程空闲，才会执行新的
        异步任务）
         */

        System.out.println("main start");
        /*Thread01 thread01 = new Thread01();
        thread01.start();
        Thread thread = new Thread(new Runable01());
        thread.start();

        FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
        new Thread(futureTask).start();
        //main线程等待callable线程执行完成，获取返回结果
        Integer res = futureTask.get();
        System.out.println("获取到线程返回的结果："+ res);
        */

        //使用线程池
        executorService.execute(new Runable01());
        System.out.println("main end");

        /*
         线程池的七大参数
            corePoolSize：【5】核心线程数；线程池创建好以后就准备就绪的线程，等待接收异步任务去执行
            相当于new了5个线程 Thread thread = new Thread()
            核心线程数是一直存在的线程，除非设置了 allowCoreThreadTimeOut，核心线程超时被回收

            maximumPoolSize: 最大线程数，用来控制资源并发

            keepAliveTime：存活时间，如果当前线程数量大于核心数量，将会释放多余空闲的线程
            （ 线程空闲时间大于keepAliveTime，且数量为maximumPoolSize - corePoolSize）

            unit：时间单位

            BlockingQueue： 如果任务有很多，就会将目前多的任务（任务数 - maximumPoolSize）放在队列中
            只要有线程空闲，就会去队列中取出新的任务继续执行

            ThreadFactory： 线程的创建工厂

            RejectedExecutionHandler：如果队列满了，按照我们指定的拒绝策略拒绝执行任务


        工作顺序
            1）线程池创建，准备好core数量的核心线程，准备接收任务
            2）新的任务进来，用core准备好的空闲线程执行
                ①、core满了，就将再进来的任务放到阻塞队列中。空闲的core会自己从阻塞队列中获取任务执行
                ②、阻塞队列满了，就直接开新线程执行，最大只能开到max指定的数量
                ③、max都执行好了。max-core数量的空闲线程会在keepAliveTime指定的时间后，自动销毁
                最终保持到core的大小
                ④、如果线程数到了max的数量，还有新任务进来，就会使用reject指定的拒绝策略进行处理
            3）所有线程的创建都是由指定的factory创建的

            面试题：
            一个线程池 core:7  max:20 queue: 50 , 100并发进来是怎么进行分配的？
            7个会立即执行
            50个会进入队列
            会开辟13个线程进行执行
            剩下的30使用拒绝策略来执行
         */
        new ThreadPoolExecutor(5,200,10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        // core = 0, 所有的线程都可以被回收
        Executors.newCachedThreadPool();
        // core = max 且一直存在，不可被回收
        Executors.newFixedThreadPool(10);
        // core = 1 单线程线程池，且一直存在，不可被回收
        Executors.newSingleThreadExecutor();
    }



    public static class Thread01 extends Thread{

        @Override
        public void run() {
            System.out.println("当前线程："+ Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果："+ i);
        }
    }

    public static class Runable01 implements Runnable{

        @Override
        public void run() {
            System.out.println("当前线程："+ Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果："+ i);
        }
    }

    public static class Callable01 implements Callable<Integer>{

        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程："+ Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果："+ i);
            return i;
        }
    }
}